package network

import (
	"net"
	"operator/pkg/codes/tcp"
	"time"
)

type AliveStatus string

const (
	ALIVE   AliveStatus = "alive"
	DIED                = "died"
	UNKNOWN             = "unknown"
)

type NetStatus struct {
	conn      net.Conn
	status    AliveStatus
	ticker    *time.Ticker
	probeRate time.Duration
}

func (tcp *NetStatus) Write(data []byte) error {
	_, err := tcp.conn.Write(data)
	if err != nil {
		tcp.status = DIED
		return err
	}

	return err
}

func (t *NetStatus) Probe() {
	data := tcp.Encode("probe", []byte{})
	_, err := t.conn.Write(data.ToBytes())
	if err != nil {
		t.status = DIED
		return
	}

	if t.status == DIED || t.status == UNKNOWN {
		t.status = ALIVE
	}
}

func (tcp *NetStatus) serve() {
	for {
		select {
		case <-tcp.ticker.C:
			tcp.Probe()
			tcp.ticker.Reset(tcp.probeRate)
		}
	}
}

func NewNetStatus(
	c net.Conn,
	probeRate time.Duration,
) *NetStatus {
	ts := &NetStatus{
		conn:      c,
		status:    UNKNOWN,
		ticker:    time.NewTicker(probeRate),
		probeRate: probeRate,
	}

	go ts.serve()

	return ts
}
